package org.minbox.framework.microservice.gateway.filter;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.minbox.framework.microservice.common.constant.BizConstant;
import org.minbox.framework.microservice.common.entity.CommonResponse;
import org.minbox.framework.microservice.common.enums.CommonExceptionTypeEnum;
import org.minbox.framework.microservice.common.util.JwtUtil;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.List;

/**
 * 用户访问过滤器
 *
 * @author XiaoQingqing
 * @since 2024/07/25
 */
@Slf4j
@Component
public class UserAccessFilter implements Ordered, GlobalFilter {
    /**
     * 序列化器
     */
    private final ObjectMapper objectMapper = new ObjectMapper();

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //1.获取request和response对象
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();
        // 处理CORS的options请求
        HttpHeaders requestHeaders = request.getHeaders();
        HttpHeaders responseHeaders = response.getHeaders();
        if (request.getMethodValue().equals(RequestMethod.OPTIONS.name())) {
            String origin = requestHeaders.getOrigin();
            responseHeaders.add("Access-control-Allow-Origin", origin);
            responseHeaders.add("Access-Control-Allow-Methods", request.getMethodValue());
            responseHeaders.add("Access-Control-Allow-Credentials", "true");
            List<String> accessControlRequestHeaders = requestHeaders.getAccessControlRequestHeaders();
            if(!CollectionUtils.isEmpty(accessControlRequestHeaders)){
                responseHeaders.add("Access-Control-Allow-Headers", accessControlRequestHeaders.get(0));
            }
            response.setStatusCode(HttpStatus.OK);
            return response.setComplete();
        }
        //2.判断是否是登录
        if (request.getURI().getPath().contains("/login")) {
            return chain.filter(exchange);
        }
        //3.获取token
        String token = request.getHeaders().getFirst(JwtUtil.DEFAULT_TOKEN_BODY_KEY);
        //4.判断token是否存在
        if (!StringUtils.hasText(token)) {
            HttpHeaders headers = response.getHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            DataBufferFactory bufferFactory = response.bufferFactory();
            return response.writeWith(Mono.fromSupplier(() -> bufferFactory.wrap(buildForbiddenResponseBodyBytes())));
        }
        //5.判断token是否有效
        try {
            Long userId = JwtUtil.decodeDefault(token, Long.class);
            // 在header中添加新的信息
            ServerHttpRequest serverHttpRequest = request.mutate().headers(httpHeaders ->
                httpHeaders.add(BizConstant.USER_ID_HEADER_NAME, userId + "")
            ).build();
            // 重置header
            exchange.mutate().request(serverHttpRequest).build();
        } catch (Exception e) {
            HttpHeaders headers = response.getHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            DataBufferFactory bufferFactory = response.bufferFactory();
            return response.writeWith(Mono.fromSupplier(() -> bufferFactory.wrap(buildForbiddenResponseBodyBytes())));
        }
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return 0;
    }

    /**
     * 构造认证失败返回内容字节数组
     *
     * @return 字节数组
     */
    private byte[] buildForbiddenResponseBodyBytes() {
        CommonResponse<Void> body = CommonResponse.of(CommonExceptionTypeEnum.LOGIN_EXCEPTION.getCode(), CommonExceptionTypeEnum.LOGIN_EXCEPTION.getName());
        try {
            return objectMapper.writeValueAsBytes(body);
        } catch (JsonProcessingException e) {
            log.error("返回认证失败发生异常", e);
            return new byte[0];
        }
    }
}
